/*
* Copyright(c) 2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES 
*/
package uiEdit
{
	import asSkinStyle.ReflPositionInfo;
	
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.display.Stage;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.filters.GlowFilter;
	import flash.geom.Point;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.text.TextField;
	import flash.text.TextFormat;
	import flash.text.TextFormatAlign;
	import flash.ui.Keyboard;
	import flash.utils.getQualifiedClassName;
	
	import sparrowGui.components.SButtonText;
	import sparrowGui.components.STextField;
	import sparrowGui.components.SWindow;
	import sparrowGui.components.ScrollList;
	import sparrowGui.components.item.SCheckButton;
	import sparrowGui.event.ItemEvent;
	import sparrowGui.event.ListEvent;
	import sparrowGui.utils.SparrowUtil;
	
	/**
	 * UI编辑控制器,可对场景上的UI对象进行调整坐标等属性
	 * 键盘ctrl+1,2,3,4分别带表界面上四个按钮点击的效果。ctrl+D，通过当前项的父类选下一个UI对象
	 * 编辑器输入特殊命令可进行特殊的解析
	 * "src:$1"通过路径加载坐标信息
	 * "src2"自动跟据对象的类型在默认认识路径找到xml加载文件加载坐标信息 (ctrl+5功能一样)
	 * "call"显示当前项的子项，可在列表中选中要编辑的项
	 * @author Pelephone
	 */
	public class UIEditor extends SWindow
	{
		public function UIEditor()
		{
			super();
			
			this.addEventListener(Event.ADDED_TO_STAGE,onThisToStage);
			this.addEventListener(Event.REMOVED_FROM_STAGE,onThisToStage);
		}
		
		/**
		 * 解析方式 0.xml解析 1.json解析
		 */
		public var parseMode:int = 0;
		
		//
		private var cbMode:SCheckButton;
		private var txtXYLabel:STextField;
		private var txtLabel1:STextField;
		private var txtWHLabel:STextField;
		private var txtLabel2:STextField;
		private var btnFather:SButtonText;
		private var btnDeCode:SButtonText;
		private var btnChild:SButtonText;
		private var btnCode:SButtonText;
		private var txtTip:STextField;
		private var txtInput:STextField;
		private var txtX:STextField;
		private var txtY:STextField;
		private var txtWidth:STextField;
		private var txtHeight:STextField;
		
		/**
		 * 选中点下子项列表
		 */
		private var underPointLs:ScrollList;
		
		/**
		 * @inheritDoc
		 */
		override protected function buildSetUI(uiVars:Object=null):void
		{
			width = 300;
			height = 200;
			
			super.buildSetUI(uiVars);

			var tfm:TextFormat;
			// 代码生成于:ui.fla>编辑场景对象面板
			
			// 设置属性
			
			cbMode = new SCheckButton();
			cbMode.name = "cbMode";
			cbMode.x = 225;
			cbMode.y = 8.35;
			contDP.addChild(cbMode);
			
			// x×y:
			txtXYLabel = new STextField();
			txtXYLabel.name = "txtXYLabel";
			txtXYLabel.x = 10;
			txtXYLabel.y = 33;
			txtXYLabel.selectable = false;
			txtXYLabel.width = 30;
			txtXYLabel.height = 22;
			contDP.addChild(txtXYLabel);
			
			// ×
			txtLabel1 = new STextField();
			txtLabel1.name = "txtLabel1";
			txtLabel1.x = 74;
			txtLabel1.y = 34;
			txtLabel1.selectable = false;
			txtLabel1.width = 26;
			txtLabel1.height = 22;
			tfm = new TextFormat();
			tfm.align = TextFormatAlign.CENTER;
			tfm.size = 12;
			txtLabel1.defaultTextFormat = tfm;
			contDP.addChild(txtLabel1);
			
			// 宽×高:
			txtWHLabel = new STextField();
			txtWHLabel.name = "txtWHLabel";
			txtWHLabel.x = 150;
			txtWHLabel.y = 33;
			txtWHLabel.selectable = false;
			txtWHLabel.width = 48;
			txtWHLabel.height = 22;
			contDP.addChild(txtWHLabel);
			
			// ×
			txtLabel2 = new STextField();
			txtLabel2.name = "txtLabel2";
			txtLabel2.x = 225.95;
			txtLabel2.y = 34;
			txtLabel2.selectable = false;
			txtLabel2.width = 26;
			txtLabel2.height = 22;
			tfm = new TextFormat();
			tfm.align = TextFormatAlign.CENTER;
			tfm.size = 12;
			txtLabel2.defaultTextFormat = tfm;
			contDP.addChild(txtLabel2);
			
			btnFather = new SButtonText();
			btnFather.name = "btnFather";
			btnFather.x = 10;
			btnFather.y = 148;
			contDP.addChild(btnFather);
			
			btnDeCode = new SButtonText();
			btnDeCode.name = "btnDeCode";
			btnDeCode.x = 225;
			btnDeCode.y = 148;
			contDP.addChild(btnDeCode);
			
			btnChild = new SButtonText();
			btnChild.name = "btnChild";
			btnChild.x = 75;
			btnChild.y = 148;
			contDP.addChild(btnChild);
			
			btnCode = new SButtonText();
			btnCode.name = "btnCode";
			btnCode.x = 160;
			btnCode.y = 148;
			contDP.addChild(btnCode);
			
			// 选中
			txtTip = new STextField();
			txtTip.name = "txtTip";
			txtTip.x = 10;
			txtTip.y = 8;
			txtTip.border = true;
			txtTip.width = 210;
			txtTip.height = 22;
			contDP.addChild(txtTip);
			
			// id:asd
			txtInput = new STextField();
			txtInput.name = "txtInput";
			txtInput.x = 10;
			txtInput.y = 60;
			txtInput.type = "input";
			txtInput.border = true;
			txtInput.width = 275;
			txtInput.height = 82;
			contDP.addChild(txtInput);
			
			// 9999
			txtX = new STextField();
			txtX.name = "txtX";
			txtX.x = 37;
			txtX.y = 33;
			txtX.type = "input";
			txtX.border = true;
			txtX.width = 37;
			txtX.height = 20;
			tfm = new TextFormat();
			tfm.align = TextFormatAlign.CENTER;
			tfm.size = 12;
			txtX.defaultTextFormat = tfm;
			contDP.addChild(txtX);
			
			// 9999
			txtY = new STextField();
			txtY.name = "txtY";
			txtY.type = "input";
			txtY.x = 97;
			txtY.y = 33;
			txtY.border = true;
			txtY.width = 37;
			txtY.height = 20;
			tfm = new TextFormat();
			tfm.align = TextFormatAlign.CENTER;
			tfm.size = 12;
			txtY.defaultTextFormat = tfm;
			contDP.addChild(txtY);
			
			// 9999
			txtWidth = new STextField();
			txtWidth.name = "txtWidth";
			txtWidth.x = 189;
			txtWidth.type = "input";
			txtWidth.y = 33;
			txtWidth.border = true;
			txtWidth.width = 37;
			txtWidth.height = 20;
			tfm = new TextFormat();
			tfm.align = TextFormatAlign.CENTER;
			tfm.size = 12;
			txtWidth.defaultTextFormat = tfm;
			contDP.addChild(txtWidth);
			
			// 9999
			txtHeight = new STextField();
			txtHeight.name = "txtHeight";
			txtHeight.type = "input";
			txtHeight.x = 248;
			txtHeight.y = 33;
			txtHeight.border = true;
			txtHeight.width = 37;
			txtHeight.height = 20;
			tfm = new TextFormat();
			tfm.align = TextFormatAlign.CENTER;
			tfm.size = 12;
			txtHeight.defaultTextFormat = tfm;
			contDP.addChild(txtHeight);
			
			underPointLs = new ScrollList();
			underPointLs.list.itemClass = UnderItem;
			underPointLs.list.colNum = 3;
			underPointLs.list.spacing = 2;
			underPointLs.visible = false;
			underPointLs.x = 12;
			underPointLs.y = 78;
			underPointLs.width = 270;
			underPointLs.height = 62;
			contDP.addChild(underPointLs);
			
			contDP.y = 20;
			txtInput.multiline = true;
			
			txtXYLabel.text = "x×y:";
			txtLabel1.text = "×";
			txtWHLabel.text = "宽×高:";
			txtLabel2.text = "×";
			txtInput.text = "选中对象的信息";
			txtInput.wordWrap = true;

			cbMode.label = "多选模式";
			
			btnChild.text = "　子项　";
			btnFather.text = "　父项　";
			btnCode.text = "子项代码";
			btnDeCode.text = "反向代码";
			
			var txts:Vector.<TextField> = new <TextField>[txtX,txtY,txtWidth,txtHeight];
			for each (var txtItm:TextField in txts) 
			{
				txtItm.restrict = "0-9";
				txtItm.addEventListener(Event.CHANGE,onInpTxtChange);
			}
			
			underPointLs.list.addEventListener(ListEvent.LIST_ITEM_SELECT,onUnderItemSelect);
			cbMode.addEventListener(ItemEvent.ITEM_SELECT_CHANGE,onModeChange);
			btnCode.addEventListener(MouseEvent.CLICK,onCodeClick);
			btnDeCode.addEventListener(MouseEvent.CLICK,onDeCodeClick);
			btnChild.addEventListener(MouseEvent.CLICK,onChildClick);
			btnFather.addEventListener(MouseEvent.CLICK,onFatherClick);
			deCodeLoader.addEventListener(Event.COMPLETE,onDeLoaderEvt);
			deCodeLoader.addEventListener(IOErrorEvent.IO_ERROR,onDeLoaderEvt);
			
			title = "UI编辑器";
			showModeUpdate();
			
			this.mouseEnabled = false;
		}
		
		/**
		 * 选子项
		 * @param event
		 */
		private function onChildClick(e:Event=null):void
		{
			var dspc:DisplayObjectContainer = editTarget as DisplayObjectContainer;
			if (!dspc || !dspc.parent)
				return;
			
			var cname:String = txtInput.text;
			if(cname == "call")
			{
				editTarget = null;
				underPointLs.visible = true;
				var dspLs:Array = [dspc];
				for (var i:int = 0; i < dspc.numChildren; i++)
				{
					dspLs.push(dspc.getChildAt(i));
				}
				
				underPointLs.data = dspLs;

			}
			else
			{
				var childDsp:DisplayObject = dspc.getChildByName(cname);
				if(!childDsp)
				{
					var tid:int = int(cname);
					if(tid >= dspc.numChildren)
						tid = dspc.numChildren - 1;
					if(dspc.numChildren > 0)
						childDsp = dspc.getChildAt(tid);
				}
			
				if(!childDsp)
					txtInput.text = ("当前显示对象无\""+cname+"\"子项");
				else
					editTarget = childDsp;
			}
		}
		
		
		/**
		 * 选父项
		 * @param event
		 */
		private function onFatherClick(event:MouseEvent=null):void
		{
			if(editTarget && editTarget.parent)
				editTarget = editTarget.parent;
		}
		
		/**
		 * 生成代码
		 * @param event
		 */
		private function onCodeClick(event:MouseEvent=null):void
		{
			if(!(editTarget is DisplayObjectContainer))
				return;
			if(parseMode == 0)
				var str:String = ReflPositionInfo.encodeChildToXml(editTarget as DisplayObjectContainer);
			else
				str = ReflPositionInfo.encodeChildToJson(editTarget as DisplayObjectContainer);
//			var str:Object = ReflPositionInfo.encodeChildToObj(editTarget as DisplayObjectContainer);
			txtInput.text = str;
		}
		
		/**
		 * 皮肤路径地址
		 */
		public var skinCfgPath:String = "assets/skinCfg/$1.xml";
		
		/**
		 * 反向代码
		 * @param event
		 */
		private function onDeCodeClick(event:MouseEvent=null):void
		{
			if(!(editTarget is DisplayObjectContainer))
				return;
			var destr:String = txtInput.text;
			if(destr == "call")
				onChildClick();
			else if(destr.indexOf("src:")==0)
			{
				var src:String = destr.replace("src:");
				loadSrc(src);
			}
			else if(destr.indexOf("src2")==0)
			{
				if(destr.length == 4)
				{
					if(editTarget.hasOwnProperty("skinName"))
						src = editTarget["skinName"];
					if(editTarget.hasOwnProperty("openName"))
						src = editTarget["openName"];
					if(editTarget.name.indexOf("instance")!=0)
						src = editTarget.name;
					else
					{
						src = getQualifiedClassName(editTarget);
						var tid2:int = src.indexOf("::");
						if(tid2>0)
							src = src.substr(tid2 + 2);
					}
				}
				else
					src = destr.substr(5);
				src = skinCfgPath.replace("$1",src);
				loadSrc(src);
			}
			else if(destr && destr.length)
			{
				if(parseMode == 0)
				{
					var deXml:XML = XML(destr);
					ReflPositionInfo.decodeXmlToChild(editTarget as DisplayObjectContainer,deXml);
				}
				else
					ReflPositionInfo.decodeJsonToChild(editTarget as DisplayObjectContainer,destr);
				updateEditUI();
			}
		}
		
		/**
		 * 加载外部数据
		 * @param src
		 */
		private function loadSrc(src:String):void
		{
//			deCodeLoader.dataFormat = URLLoaderDataFormat.BINARY;
			loadingSrc = src;
			var ul:URLRequest = new URLRequest(src);
			deCodeLoader.load(ul);
			this.mouseChildren = false;
		}
		
		/**
		 * 当前正在加载的对象
		 */
		private var loadingSrc:String;
		
		/**
		 * 加部加载完成
		 * @param event
		 */
		private function onDeLoaderEvt(event:Event):void
		{
			switch(event.type)
			{
				case Event.COMPLETE:
				{
					var sData:String = String(deCodeLoader.data);
					if(parseMode == 0)
					{
						var deXml:XML = XML(sData);
						ReflPositionInfo.decodeXmlToChild(editTarget as DisplayObjectContainer,deXml);
					}
					else
						ReflPositionInfo.decodeJsonToChild(editTarget as DisplayObjectContainer,sData);
					
					updateEditUI();
					
					if(parseMode == 0)
						txtInput.text = deXml;
					else
						txtInput.text = sData;
					
					trace(loadingSrc,"加载完成");
					break;
				}
					
				default:
				{
					txtInput.text = loadingSrc + "加载错误";
					break;
				}
			}
			this.mouseChildren = true;
		}
		
		/**
		 * 外部代码加载器
		 */
		private var deCodeLoader:URLLoader = new URLLoader();
		
		/**
		 * 输入数字改变
		 */
		private function onInpTxtChange(event:Event):void
		{
			if(!editTarget)
				return;
			editTarget.x = int(txtX.text);
			editTarget.y = int(txtY.text);
			editTarget.width = int(txtWidth.text);
			editTarget.height = int(txtHeight.text);
		}
		
		/**
		 * 子项选中
		 * @param event
		 */
		private function onUnderItemSelect(e:ListEvent):void
		{
			var dsp:DisplayObject = e.itemData as DisplayObject;
			editTarget = dsp;
			underPointLs.visible = false;
		}
		
		/**
		 * 选中模式改变
		 * @param event
		 */
		private function onModeChange(event:ItemEvent=null):void
		{
			showModeUpdate();
			editTarget = null;
		}
		
		/**
		 * 模式改变
		 */
		private function showModeUpdate():void
		{
			if(cbMode && cbMode.selected)
				txtTip.text = "点选,并从列表中选取该点下的对象";
			else
			{
				txtTip.text = "点选场景上的UI对象，对其进行编辑";
				underPointLs.visible = false;
			}
		}
		
		/**
		 * 对象添加和离开舞台
		 * @param event
		 */
		private function onThisToStage(event:Event):void
		{
			if(event.type == Event.ADDED_TO_STAGE)
			{
				SparrowUtil.addNextCall(onNextStageEvent);
			}
			if(event.type == Event.REMOVED_FROM_STAGE)
			{
				this.stage.removeEventListener(MouseEvent.CLICK,onStageClick);
				this.stage.removeEventListener(KeyboardEvent.KEY_DOWN, onkeyUpHandler);
			}
		}
		
		/**
		 * 延迟一帧处理鼠标事件,防止马上监听，马上触发onStageClick
		 */
		private function onNextStageEvent(e:*=null):void
		{
			if(this.stage)
			{
				this.stage.addEventListener(MouseEvent.CLICK,onStageClick);
				this.stage.addEventListener(KeyboardEvent.KEY_DOWN, onkeyUpHandler);
			}
		}
		
		/**
		 * 键盘事件
		 * @param event
		 */
		private function onkeyUpHandler(event:KeyboardEvent):void
		{
			if (event.shiftKey)
			{
				var xOffext:int = 0;
				var yOffext:int = 0;
				if (event.keyCode == Keyboard.LEFT)
					xOffext = -10;
				if (event.keyCode == Keyboard.RIGHT)
					xOffext = 10;
				if (event.keyCode == Keyboard.UP)
					yOffext = -10;
				if (event.keyCode == Keyboard.DOWN)
					yOffext = 10;
			}
			else if (event.ctrlKey)
			{
				var wOffext:int = 0;
				var hOffext:int = 0;
				if (event.keyCode == Keyboard.LEFT)
					wOffext = -1;
				if (event.keyCode == Keyboard.RIGHT)
					wOffext = 1;
				if (event.keyCode == Keyboard.UP)
					hOffext = -1;
				if (event.keyCode == Keyboard.DOWN)
					hOffext = 1;
				
				// 各按钮点击
				if (event.keyCode == Keyboard.NUMBER_1)
					onFatherClick();
				else if (event.keyCode == Keyboard.NUMBER_2)
					onChildClick();
				else if (event.keyCode == Keyboard.NUMBER_3)
					onCodeClick();
				else if (event.keyCode == Keyboard.NUMBER_4)
					onDeCodeClick();
				else if (event.keyCode == Keyboard.NUMBER_6)
				{
					if(parseMode == 0)
					{
						txtInput.text = "切换为json解析模式";
						parseMode = 1;
					}
					else
					{
						txtInput.text = "切换为xml解析模式";
						parseMode = 0;
					}
				}
				else if (event.keyCode == Keyboard.NUMBER_5)
				{
					txtInput.text = "src2";
					onDeCodeClick();
				}
				// 重挑下一个子项
				else if (event.keyCode == Keyboard.D)
				{
					if(editTarget && editTarget.parent)
					{
						var tid:int = editTarget.parent.getChildIndex(editTarget);
						tid = tid + 1;
						if(tid >= editTarget.parent.numChildren)
							tid = 0;
						editTarget = editTarget.parent.getChildAt(tid);
					}
				}
			}
			else if (event.keyCode == Keyboard.LEFT)
				xOffext = -1;
			else if (event.keyCode == Keyboard.RIGHT)
				xOffext = 1;
			else if (event.keyCode == Keyboard.UP)
				yOffext = -1;
			else if (event.keyCode == Keyboard.DOWN)
				yOffext = 1;
			if(xOffext !=0 || yOffext != 0)
			{
				editTarget.x += xOffext;
				editTarget.y += yOffext;
				updateEditUI();
			}
		}
		
		/**
		 * 跟椐显示编辑对象刷新显示界面
		 */
		private function updateEditUI():void
		{
			if (editTarget)
			{
				var cls:String = getQualifiedClassName(editTarget);
				txtX.text = editTarget.x.toString();
				txtY.text = editTarget.y.toString();
				txtWidth.text = editTarget.width.toString();
				txtHeight.text = editTarget.height.toString();
				txtTip.text = "ClassName: " + cls;
				txtTip.scrollH = txtTip.text.length;
				var str:String = "";
				if(editTarget is DisplayObjectContainer)
					str = "\n子项个数" + (editTarget as DisplayObjectContainer).numChildren;
				txtInput.text = "当前选中的对象的Class是:" + cls + "\n对象的name是:" + editTarget.name + str;
			}
			else
			{
				txtX.text = "";
				txtY.text = "";
				txtWidth.text = "";
				txtHeight.text = "";
				txtInput.text = "";
				showModeUpdate();
			}
		}
		
		/**
		 * 选中时的发光滤镜
		 */
		private static var glowFilter:Array = [new GlowFilter(0xFF0000,1,2,2,1)];
		
		private var _editTarget:DisplayObject;

		/**
		 * 当前正在编辑的对象
		 */
		public function get editTarget():DisplayObject
		{
			return _editTarget;
		}

		/**
		 * @private
		 */
		public function set editTarget(value:DisplayObject):void
		{
			var isInMe:Boolean = isTargetInThis(value);
			if(value == _editTarget || isInMe)
				return;
			
			if(value is Stage)
				value = null;
			
			if(_editTarget)
				_editTarget.filters = targetOldFilters;
			
			_editTarget = value;
			
			if(value)
			{
				targetOldFilters = value.filters;
				_editTarget.filters = glowFilter;
			}
			updateEditUI();
		}
		
		/**
		 * 判断对象是否在这个面板里面
		 */
		private function isTargetInThis(target:DisplayObject):Boolean
		{
			var upPanel:DisplayObject = target;
			while(upPanel)
			{
				if(upPanel == this)
				{
					return true;
				}
				upPanel = upPanel.parent;
			}
			return false;
		}

		
		/**
		 * 对象原来的滤镜
		 */
		private var targetOldFilters:Array;
		
		/**
		 * 增加舞台点击事件
		 * @param event
		 */
		private function onStageClick(event:MouseEvent):void
		{
			var tar:DisplayObject = event.target as DisplayObject;
			if(!tar)
				return;
			
			var isInMe:Boolean = isTargetInThis(tar);
			if(isInMe)
				return;
			
			// 选中方式
			if(cbMode && cbMode.selected && tar is DisplayObjectContainer)
			{
				showUnderDsp(tar as DisplayObjectContainer);
			}
			else
			{
				editTarget = tar;
			}
		}
		
		/**
		 * 显示子项
		 * @param tar
		 */
		public function showUnderDsp(tar:DisplayObjectContainer):void
		{
			if(tar == null)
				return;
			
			var pdsp:DisplayObjectContainer = (tar.parent)?tar.parent:tar;
			if(!pdsp)
				pdsp = tar.stage;
			editTarget = null;
			underPointLs.visible = true;
			var dspLs:Array = pdsp.getObjectsUnderPoint(new Point(pdsp.mouseX,pdsp.mouseY));
			dspLs.unshift(tar);
			underPointLs.data = dspLs;
		}
	}
}